"""
AI自动开发 - 文件操作服务层
负责文件CRUD操作、内容搜索、函数搜索、目录结构分析
"""

from pathlib import Path
from typing import Dict, List, Any, Optional, Union
import os

from utils import (
    is_safe_path, normalize_path, get_file_info, backup_file,
    extract_functions_from_code, search_in_text, format_timestamp,
    get_file_type, is_text_file, walk_directory, handle_errors
)


class FileService:
    """文件操作服务类"""

    def __init__(self):
        self.max_file_size = 100 * 1024 * 1024  # 100MB
        self.supported_extensions = ['.py', '.md', '.txt', '.json', '.yaml', '.yml', '.html', '.css', '.js', '.ts', '.java', '.tsx']

    def _validate_path(self, filepath: str, project_path: str) -> Path:
        """验证并标准化文件路径"""
        try:
            full_path = normalize_path(filepath, project_path)
            if not is_safe_path(full_path, project_path):
                raise ValueError(f"路径不安全: {filepath}")
            return full_path
        except Exception as e:
            raise ValueError(f"路径验证失败: {str(e)}")

    def _log_file_operation(self, project_path: str, filepath: str, operation: str, summary: str):
        """记录文件操作到项目日志"""
        try:
            # 导入项目服务来记录日志
            from project_service import project_service
            project_service.log_file_change(project_path, filepath, operation, summary)
        except Exception:
            # 如果记录失败，不影响主要操作
            pass

    # ===== 基础文件操作 =====

    def create_file(self, project_path: str, filepath: str, content: str = "", summary: str = "") -> Dict[str, Any]:
        """
        创建新文件

        参数:
        - project_path: 项目路径
        - filepath: 文件路径（相对于项目路径）
        - content: 文件内容
        - summary: 操作总结

        返回:
        - dict: 操作结果
        """
        try:
            full_path = self._validate_path(filepath, project_path)

            # 检查文件是否已存在
            if full_path.exists():
                return {
                    'success': False,
                    'message': f'文件已存在: {filepath}'
                }

            # 检查内容大小
            if len(content.encode('utf-8')) > self.max_file_size:
                return {
                    'success': False,
                    'message': f'文件内容过大，超过 {self.max_file_size // (1024 * 1024)}MB 限制'
                }

            # 创建目录（如果需要）
            full_path.parent.mkdir(parents=True, exist_ok=True)

            # 写入文件
            full_path.write_text(content, encoding='utf-8')

            # 记录操作日志
            log_summary = summary or f"创建文件 ({len(content)} 字符)"
            self._log_file_operation(project_path, filepath, 'CREATE', log_summary)

            file_info = get_file_info(full_path)

            return {
                'success': True,
                'message': f'文件创建成功: {filepath}',
                'file_path': str(full_path),
                'file_info': file_info
            }

        except Exception as e:
            return {
                'success': False,
                'message': f'创建文件失败: {str(e)}'
            }

    def read_file(self, project_path: str, filepath: str) -> Dict[str, Any]:
        """
        读取文件内容

        参数:
        - project_path: 项目路径
        - filepath: 文件路径

        返回:
        - dict: 文件内容和信息
        """
        try:
            full_path = self._validate_path(filepath, project_path)

            if not full_path.exists():
                return {
                    'success': False,
                    'message': f'文件不存在: {filepath}'
                }

            if not full_path.is_file():
                return {
                    'success': False,
                    'message': f'不是文件: {filepath}'
                }

            # 检查是否为文本文件
            if not is_text_file(full_path):
                try:
                    content = full_path.read_text(encoding='utf-8')
                    file_info = get_file_info(full_path)
                    return {
                        'success': True,
                        'content': content,
                        'file_path': str(full_path),
                        'file_info': file_info,
                        'file_type': get_file_type(full_path)  # 无扩展名时多半是 'Unknown'
                    }
                except Exception:
                    return {
                        'success': False,
                        'message': f'不支持的文件类型: {filepath}'
                    }

            # 检查文件大小
            file_size = full_path.stat().st_size
            if file_size > self.max_file_size:
                return {
                    'success': False,
                    'message': f'文件过大: {filepath} ({file_size // (1024 * 1024)}MB)'
                }

            # 读取文件内容
            content = full_path.read_text(encoding='utf-8')
            file_info = get_file_info(full_path)

            return {
                'success': True,
                'content': content,
                'file_path': str(full_path),
                'file_info': file_info,
                'file_type': get_file_type(full_path)
            }

        except UnicodeDecodeError:
            return {
                'success': False,
                'message': f'文件编码错误，无法读取: {filepath}'
            }
        except Exception as e:
            return {
                'success': False,
                'message': f'读取文件失败: {str(e)}'
            }

    def edit_file(self, project_path: str, filepath: str, content: str, summary: str = "") -> Dict[str, Any]:
        """
        编辑文件内容（覆盖）

        参数:
        - project_path: 项目路径
        - filepath: 文件路径
        - content: 新的文件内容
        - summary: 操作总结

        返回:
        - dict: 操作结果
        """
        try:
            full_path = self._validate_path(filepath, project_path)

            if not full_path.exists():
                return {
                    'success': False,
                    'message': f'文件不存在: {filepath}'
                }

            # 检查内容大小
            if len(content.encode('utf-8')) > self.max_file_size:
                return {
                    'success': False,
                    'message': f'文件内容过大，超过 {self.max_file_size // (1024 * 1024)}MB 限制'
                }

            # 备份原文件（可选）
            backup_path = backup_file(full_path)

            # 写入新内容
            full_path.write_text(content, encoding='utf-8')

            # 记录操作日志
            log_summary = summary or f"编辑文件 ({len(content)} 字符)"
            self._log_file_operation(project_path, filepath, 'EDIT', log_summary)

            file_info = get_file_info(full_path)

            result = {
                'success': True,
                'message': f'文件编辑成功: {filepath}',
                'file_path': str(full_path),
                'file_info': file_info
            }

            if backup_path:
                result['backup_path'] = str(backup_path)

            return result

        except Exception as e:
            return {
                'success': False,
                'message': f'编辑文件失败: {str(e)}'
            }

    def delete_file(self, project_path: str, filepath: str, summary: str = "") -> Dict[str, Any]:
        """
        删除文件

        参数:
        - project_path: 项目路径
        - filepath: 文件路径
        - summary: 操作总结

        返回:
        - dict: 操作结果
        """
        try:
            full_path = self._validate_path(filepath, project_path)

            if not full_path.exists():
                return {
                    'success': False,
                    'message': f'文件不存在: {filepath}'
                }

            if not full_path.is_file():
                return {
                    'success': False,
                    'message': f'不是文件: {filepath}'
                }

            # 获取文件信息（删除前）
            file_info = get_file_info(full_path)

            # 备份文件（删除前）
            backup_path = backup_file(full_path)

            # 删除文件
            full_path.unlink()

            # 记录操作日志
            log_summary = summary or f"删除文件 ({file_info.get('size', 0)} bytes)"
            self._log_file_operation(project_path, filepath, 'DELETE', log_summary)

            result = {
                'success': True,
                'message': f'文件删除成功: {filepath}',
                'deleted_file_info': file_info
            }

            if backup_path:
                result['backup_path'] = str(backup_path)

            return result

        except Exception as e:
            return {
                'success': False,
                'message': f'删除文件失败: {str(e)}'
            }

    def backup_file_manual(self, project_path: str, filepath: str) -> Dict[str, Any]:
        """
        手动备份文件

        参数:
        - project_path: 项目路径
        - filepath: 文件路径

        返回:
        - dict: 备份结果
        """
        try:
            full_path = self._validate_path(filepath, project_path)

            if not full_path.exists():
                return {
                    'success': False,
                    'message': f'文件不存在: {filepath}'
                }

            backup_path = backup_file(full_path)

            if backup_path:
                # 记录操作日志
                self._log_file_operation(project_path, filepath, 'BACKUP', f"手动备份到 {backup_path.name}")

                return {
                    'success': True,
                    'message': f'文件备份成功: {filepath}',
                    'backup_path': str(backup_path)
                }
            else:
                return {
                    'success': False,
                    'message': f'文件备份失败: {filepath}'
                }

        except Exception as e:
            return {
                'success': False,
                'message': f'备份文件失败: {str(e)}'
            }

    # ===== 搜索功能 =====

    def search_content_global(self, project_path: str, query: str, extension: str = None, max_results: int = 50) -> \
    Dict[str, Any]:
        """
        全局内容搜索

        参数:
        - project_path: 项目路径
        - query: 搜索查询
        - extension: 文件扩展名（如'.py'，None表示搜索所有文本文件）
        - max_results: 最大结果数量

        返回:
        - dict: 搜索结果
        """
        try:
            project_dir = Path(project_path)
            if not project_dir.exists():
                return {
                    'success': False,
                    'message': '项目路径不存在'
                }

            search_results = []
            files_searched = 0

            # 遍历项目文件
            for file_path in project_dir.rglob('*'):
                if file_path.is_file() and not str(file_path).startswith(str(project_dir / 'venv')):
                    # 检查文件扩展名
                    should_search = False

                    if extension is None:
                        # 无扩展名限制，搜索所有支持的文本文件
                        should_search = file_path.suffix.lower() in self.supported_extensions
                    else:
                        # 指定扩展名
                        should_search = file_path.suffix.lower() == extension.lower()

                    if should_search:
                        try:
                            content = file_path.read_text(encoding='utf-8')
                            matches = search_in_text(content, query, context_lines=5)

                            if matches:
                                relative_path = str(file_path.relative_to(project_dir))
                                for match in matches:
                                    search_results.append({
                                        'file_path': relative_path,
                                        'line_number': match['line_number'],
                                        'line_content': match['line_content'],
                                        'context_lines': match['context_lines'],
                                        'context_start': match['context_start'],
                                        'context_end': match['context_end']
                                    })

                                    if len(search_results) >= max_results:
                                        break

                            files_searched += 1

                            if len(search_results) >= max_results:
                                break

                        except (UnicodeDecodeError, PermissionError):
                            # 跳过无法读取的文件
                            continue

            return {
                'success': True,
                'query': query,
                'results_count': len(search_results),
                'files_searched': files_searched,
                'results': search_results,
                'search_extension': extension,
                'all_supported_extensions': self.supported_extensions if extension is None else [extension]
            }

        except Exception as e:
            return {
                'success': False,
                'message': f'搜索失败: {str(e)}'
            }

    def search_functions(self, project_path: str, query: str, file_path: str = None) -> Dict[str, Any]:
        """
        搜索Python函数定义

        参数:
        - project_path: 项目路径
        - query: 搜索查询（函数名）
        - file_path: 指定文件路径，None表示搜索所有Python文件

        返回:
        - dict: 函数搜索结果
        """
        try:
            project_dir = Path(project_path)
            if not project_dir.exists():
                return {
                    'success': False,
                    'message': '项目路径不存在'
                }

            function_results = []
            files_searched = 0

            if file_path:
                # 搜索指定文件
                full_path = self._validate_path(file_path, project_path)
                if full_path.exists() and full_path.suffix == '.py':
                    try:
                        content = full_path.read_text(encoding='utf-8')
                        functions = extract_functions_from_code(content, str(full_path.relative_to(project_dir)))

                        # 过滤匹配的函数
                        for func in functions:
                            if 'error' in func:
                                continue
                            if query.lower() in func['name'].lower():
                                function_results.append(func)

                        files_searched = 1
                    except Exception:
                        pass
            else:
                # 搜索所有Python文件
                for py_file in project_dir.rglob('*.py'):
                    if not str(py_file).startswith(str(project_dir / 'venv')):
                        try:
                            content = py_file.read_text(encoding='utf-8')
                            functions = extract_functions_from_code(content, str(py_file.relative_to(project_dir)))

                            # 过滤匹配的函数
                            for func in functions:
                                if 'error' in func:
                                    continue
                                if query.lower() in func['name'].lower():
                                    function_results.append(func)

                            files_searched += 1

                        except Exception:
                            # 跳过无法读取或解析的文件
                            continue

            return {
                'success': True,
                'query': query,
                'results_count': len(function_results),
                'files_searched': files_searched,
                'functions': function_results,
                'search_scope': file_path or 'all_python_files'
            }

        except Exception as e:
            return {
                'success': False,
                'message': f'函数搜索失败: {str(e)}'
            }

    # ===== 目录分析 =====

    def analyze_directory_structure(self, project_path: str, target_path: str = ".", max_depth: int = 3) -> Dict[
        str, Any]:
        """
        分析目录结构

        参数:
        - project_path: 项目路径
        - target_path: 目标路径（相对于项目路径）
        - max_depth: 最大深度

        返回:
        - dict: 目录结构分析结果
        """
        try:
            if target_path == ".":
                full_path = Path(project_path)
            else:
                full_path = self._validate_path(target_path, project_path)

            if not full_path.exists():
                return {
                    'success': False,
                    'message': f'路径不存在: {target_path}'
                }

            if not full_path.is_dir():
                return {
                    'success': False,
                    'message': f'不是目录: {target_path}'
                }

            # 获取文件列表
            files = walk_directory(full_path, max_depth=max_depth, include_extensions=None)

            # 统计信息
            stats = {
                'total_files': len(files),
                'file_types': {},
                'total_size': 0,
                'max_depth_found': 0
            }

            # 构建树形结构
            tree_structure = self._build_tree_structure(full_path, files, max_depth)

            for file_info in files:
                # 统计文件类型
                ext = Path(file_info['name']).suffix or 'no_extension'
                stats['file_types'][ext] = stats['file_types'].get(ext, 0) + 1

                # 统计大小和深度
                stats['total_size'] += file_info['size']
                stats['max_depth_found'] = max(stats['max_depth_found'], file_info['depth'])

            return {
                'success': True,
                'target_path': str(full_path.relative_to(project_path)) if target_path != "." else ".",
                'max_depth': max_depth,
                'statistics': stats,
                'tree_structure': tree_structure,
                'files': files
            }

        except Exception as e:
            return {
                'success': False,
                'message': f'目录分析失败: {str(e)}'
            }

    def _build_tree_structure(self, root_path: Path, files: List[Dict], max_depth: int) -> Dict[str, Any]:
        """构建树形结构"""
        tree = {
            'name': root_path.name,
            'type': 'directory',
            'children': {}
        }

        for file_info in files:
            if file_info['depth'] > max_depth:
                continue

            # 构建路径层次
            relative_path = file_info['relative_path']
            path_parts = Path(relative_path).parts

            current_level = tree['children']

            # 遍历路径的每一部分
            for i, part in enumerate(path_parts):
                if part not in current_level:
                    if i == len(path_parts) - 1:
                        # 是文件
                        current_level[part] = {
                            'name': part,
                            'type': 'file',
                            'size': file_info['size'],
                            'extension': Path(part).suffix
                        }
                    else:
                        # 是目录
                        current_level[part] = {
                            'name': part,
                            'type': 'directory',
                            'children': {}
                        }

                if current_level[part]['type'] == 'directory':
                    current_level = current_level[part]['children']

        return tree

    # ===== 批量操作 =====

    def create_files_batch(self, project_path: str, files_data: List[Dict[str, str]]) -> Dict[str, Any]:
        """
        批量创建文件

        参数:
        - project_path: 项目路径
        - files_data: 文件数据列表，每个元素包含 {'filepath': '...', 'content': '...', 'summary': '...'}

        返回:
        - dict: 批量操作结果
        """
        results = {
            'success': True,
            'created_files': [],
            'failed_files': [],
            'total_count': len(files_data)
        }

        for file_data in files_data:
            filepath = file_data.get('filepath', '')
            content = file_data.get('content', '')
            summary = file_data.get('summary', '')

            result = self.create_file(project_path, filepath, content, summary)

            if result['success']:
                results['created_files'].append({
                    'filepath': filepath,
                    'size': len(content)
                })
            else:
                results['failed_files'].append({
                    'filepath': filepath,
                    'error': result['message']
                })
                results['success'] = False

        return results


# 全局实例
file_service = FileService()

# 测试代码
if __name__ == "__main__":
    # 测试文件服务
    test_project = "./test_project"

    print("文件服务测试:")

    # 测试创建文件
    result = file_service.create_file(
        test_project,
        "test.py",
        "def hello():\n    print('Hello World')\n",
        "创建测试Python文件"
    )
    print(f"创建文件: {result}")

    # 测试读取文件
    if result['success']:
        read_result = file_service.read_file(test_project, "test.py")
        print(f"读取文件: {read_result['success']}")

        # 测试函数搜索
        func_result = file_service.search_functions(test_project, "hello")
        print(f"函数搜索结果: {func_result} 个函数")